package jp.millibit.util
{
	import flash.utils.Proxy;
	import flash.utils.flash_proxy;
	import flash.utils.getQualifiedClassName;

	use namespace flash_proxy;

	public dynamic class WeakCache extends Proxy
	{

		private var _map:Object = {};

		private var _watcher:GCWatcher;

		private var _iteration:Array;

		public function WeakCache()
		{
			_map = new Object();
			_watcher = new GCWatcher();
			_watcher.addEventListener(GCEvent.GC, gcHandler);
		}

		private function gcHandler(e:GCEvent):void
		{
			for (var n:String in _map)
			{
				var ref:WeakReference = _map[n];
				if (ref.getObject() === null)
				{
					flash_proxy::deleteProperty(n);
				}
			}
		}

		flash_proxy override function deleteProperty(name:*):Boolean
		{
			if (name in _map)
			{
				delete _map[name];
				return true;
			}

			return false;
		}

		flash_proxy override function getProperty(name:*):*
		{
			if (!(name in _map))
			{
				return undefined;
			}

			var ref:WeakReference = _map[name];
			var obj:Object = ref.getObject();
			if (obj === null)
			{
				flash_proxy::deleteProperty(name);
				return undefined;
			}

			return obj;
		}

		flash_proxy override function hasProperty(name:*):Boolean
		{
			return flash_proxy::getProperty(name) !== undefined;
		}

		flash_proxy override function nextName(index:int):String
		{
			return _iteration[index - 1].name;
		}

		flash_proxy override function nextNameIndex(index:int):int
		{
			if (index == 0)
			{
				_iteration = [];
				for (var n:String in _map)
				{
					var ref:WeakReference = _map[n];
					if (ref.getObject() !== null)
					{
						_iteration.push({name:n, value:ref.getObject()});
					}
					else
					{
						flash_proxy::deleteProperty(n);
					}
				}
			}

			if (index < _iteration.length)
			{
				return index + 1;
			}
			else
			{
				_iteration = null;
				return 0;
			}
		}

		flash_proxy override function nextValue(index:int):*
		{
			return _iteration[index - 1].value;
		}

		flash_proxy override function setProperty(name:*, value:*):void
		{
			var ref:WeakReference = new WeakReference(value, _watcher);
			_map[name] = ref;
		}
	}
}